package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

// 将name作为字符串传进函数里，
// 函数的参数 str会复制一份name的值， 所以str改变的值是自己的内存地址的值，跟name无关
func P1(str string) {
	str = "xixihaha"
}

func P1a() {
	var name string = "name"
	P1(name)
	fmt.Println(name)
}

// 当 name作为一个内存地址传入到 P2a时， P2a的参数是一个指针
// 指针会指向name的内存地址， 当改变指针的值时，改变的时原内存地址的值，所以name的值改变
func P2() {
	var name string = "myc"
	P2a(&name)
	fmt.Println(name)
}

func P2a(probe *string) {
	*probe = "djr"
}

// fmt.Scan输入的参数需要是指针类型
func P3() {
	var v1 string
	fmt.Scan(&v1)
	fmt.Println(v1, reflect.TypeOf(v1))
}

// 指针指向数组的内存, 并获取下一个元素的值
func P4() {
	// 数组的内存地址为 数组的第一个元素的内存地址
	var array1 = [3]int16{1, 2, 3}
	fmt.Printf("array1: %p, array1[0]: %p\n", &array1, &array1[0])
	fmt.Printf("array1[0]: %p， array1[1]: %p， array1[2]: %p\n", &array1[0], &array1[1], &array1[2])

	// 创建一个指针， 指向数组的第一个内存地址
	var prodFirstData *int16
	prodFirstData = &array1[0]
	fmt.Printf("prodFirstData: %p\n", prodFirstData)

	// 将指针转换为point类型
	firstDataPtr := unsafe.Pointer(prodFirstData)
	fmt.Printf("pointType: %+v\n", firstDataPtr)

	// 将point类型转换成uintptr类型, 之后根据位数计算， 找到第二个元素的位置
	cacuFirstPtr := uintptr(firstDataPtr) + 2
	fmt.Printf("cacuFirstPtr: %+v\n", cacuFirstPtr)

	// 拿到新的内存地址，再转换成point类型
	secondPtr := unsafe.Pointer(cacuFirstPtr)
	fmt.Printf("secondPtr: %+v\n", secondPtr)

	// 最后再转换成int16类型的指针
	result := (*int16)(secondPtr)

	// 获取指针的值
	fmt.Printf("result: %d\n", *result)
}
